Vue.jsとCustom Elementsの関係性について
タスク:Custom Elements × Vue について書いてほしい · Issue #70 · shinGangan/comm_vue_nuxt · GitHub
記事:Vue3.5からの改善と振り返るdefineCustomElementについて
ネタ出し
そもそもCustom Elementsとは?
Custom Elementsは、Web標準のWeb Componentsを構成する一部であり、独自のHTMLタグを作成して再利用できる技術
https://html.spec.whatwg.org/multipage/custom-elements.html#custom-elements
カスタム要素の使用 - Web API | MDN
JavaScript API
実際の使用例
GitHub
https://github.com/github/relative-time-element
https://gyazo.com/51a182f6b9bf3c266eaa65d41434b1b2
https://gyazo.com/474e1423dc198e6fc5805c9349688c20
Vue.js で Custom Elements を使う方法
https://custom-elements-everywhere.com/
Vue.jsはサポート100%の状態
https://ja.vuejs.org/guide/extras/web-components
使うためには設定をいれる必要がある
app.config.compilerOptions.isCustomElement = (tag) => tag.includes('-')
code:vite.config.js
export default {
plugins: [
vue({
template: {
compilerOptions: {
isCustomElement: (tag) => tag.includes('-')
}
}
})
]
}
defineCustomElementを使う
拡張子をce.vueで定義する
code:ts
import { defineCustomElement } from 'vue';
import Example from './Example.ce.vue';
console.log(Example.styles); // inlined css */"
// カスタム要素のコンストラクタに変換
const ExampleElement = defineCustomElement(Example);
// 登録
customElements.define('my-example', ExampleElement);
v3.5 で入った改善について
https://blog.vuejs.org/posts/vue-3-5#custom-elements-improvements
3.5では、defineCustomElement() APIに関連する多くの長年の問題が修正され、Vueでカスタム要素をオーサリングするための多くの新機能が追加されました。
configureAppオプションによるCustom Elementsのアプリ設定をサポート
Custom Elementsのhost要素とShadow rootにアクセスするためのuseHost()、useShadowRoot()、this.$host APIを追加しました
shadowRoot: falseを渡すことで、Shadow DOMなしでCustom Elementsをマウントできます
Custom Elementsによって注入される<style>タグに添付されるnonceオプションを提供します。
code:ts
import MyElement from './MyElement.ce.vue';
defineCustomElements(MyElement, {
shadowRoot: false,
nonce: 'xxx',
configureApp(app) {
app.config.errorHandler = ...
}
});
https://github.com/vuejs/core/blob/dad673809929c084dcb8e42640eb7daa675d4ea4/CHANGELOG.md#custom-element
Custom Elementsに関する更新内容
custom-element: useShadowRoot() helper (5a1a89b), closes #6113 #8195
useShadowRoot()ヘルパー
custom-element: useHost() helper (775103a)
useHost()ヘルパー
custom-element: expose this.$host in Options API (1ef8f46)
this.$hostを作成
custom-element: inject child components styles to custom element shadow root (#11517) (56c76a8), closes #4662 #7941 #7942
ネストされたコンポーネントのスタイルをshadow rootに継承させる
code:ts
import { defineCustomElement } from 'vue'
import Root from './Root.ce.vue'
customElements.define('my-el', defineCustomElement(Root))
code:html
<!-- Root.ce.vue -->
<script setup>
import Child from './Child.ce.vue'
</script>
code:html
<!-- Child.ce.vue -->
<style>
div { color: red }; /* will be injected to Root.ce.vue's shadow root */
</style>
custom-element: support configurable app instance in defineCustomElement (6758c3c), closes #4356 #4635
defineCustomElement()にconfigureApp設定を追加
custom-element: support css :host selector by applying css vars on host element (#8830) (03a9ea2), closes #8826
:hostをサポート
custom-element: support emit with options (e181bff), closes #7605
最初のイベント引数がオブジェクトである場合、それはCustomEventのオプションオブジェクトとして使用される
引数リスト全体は CustomEvent の detail プロパティを通して公開される
code:js
emit('event', { bubbles: true })
custom-element: support expose on customElement (#6256) (af838c1), closes #5540
defineCustomElementにexposeをサポート
custom-element: support nonce option for injected style tags (bb4a02a), closes #6530
nonceオプションをサポート
custom-element: support passing custom-element-specific options via 2nd argument of defineCustomElement (60a88a2)
defineCustomElementの第2引数にCustomElementOptionsを渡せるように
custom-element: support shadowRoot: false in defineCustomElement() (37d2ce5), closes #4314 #4404
shadowRoot: falseをサポート
Evan Youが大半を修正してくれてるけどモチベーションがなんなのかきになったyamanoku.icon
今残ってるIssue
https://github.com/vuejs/core/labels/scope%3A%20custom%20elements
CSS @import and background-image path not resolved in Custom Elements · Issue #4394 · vuejs/core · GitHub
CSSでの@import や background-imageのパスが解決しない問題
Custom elements sometimes not rendered correctly inside a v-for loop · Issue #6309 · vuejs/core · GitHub
v-forループ内でCustom Elementsが正しくレンダリングされないことがある
Slots in loops only assigned once when component used as custom element · Issue #10691 · vuejs/core · GitHub
ループ内のスロット・コンテンツが、v-for分だけレンダリングされ、v-for分だけ置換される。
code:html
<template>
<div v-for="i in 1, 2, 3">
<slot name="root">Replace me</slot>
</div>
</template>
#6309関連あるかな
Custom elements not able to associate with form · Issue #10948 · vuejs/core · GitHub
Custom Elementsにてform submitがうまくいかない
ElementInternalsの話
事例
ep.104 『defineCustomElement で広がる Vue 3 によるコラボレーションの世界』 | UIT INSIDE
「defineCustomElement」を活用した サービス共通のUIコンポーネントライブラリ - Speaker Deck